package system

import (
	"encoding/json"
	mqtt "github.com/eclipse/paho.mqtt.golang"
	"go.uber.org/zap"
	"log"
	"process/global"
	"process/model/system"
	systemReq "process/model/system/request"
	"strconv"
	"strings"
	"time"
)

type SnProcess struct{}

func (sp *SnProcess) SetLockState() {
	conn, _ := RabbitMQService.GetConnection()
	defer conn.Close()
	ch, err := conn.Channel()
	if err != nil {
		global.GVA_LOG.Info("setLockState Failed to open a channel", zap.Error(err))
	}
	defer ch.Close()

	//此处的exchange名称在php项目中
	err = ch.ExchangeDeclare(
		"exc_product", // name
		"direct",      // type
		true,          // durable
		false,         // auto-deleted
		false,         // internal
		false,         // no-wait
		nil,           // arguments
	)
	if err != nil {
		global.GVA_LOG.Info("setLockState Failed to declare an exchange", zap.Error(err))
	}

	//如果queue不存在则声明
	q, err := ch.QueueDeclare(
		"setLockState", // name
		true,           // durable
		false,          // delete when unused
		true,           // exclusive
		false,          // no-wait
		nil,            // arguments
	)
	if err != nil {
		global.GVA_LOG.Info("setLockState Failed to declare a queue", zap.Error(err))
	}

	err = ch.QueueBind(
		q.Name,
		"pus_product", // routing key
		"exc_product", // exchange
		false,
		nil)
	if err != nil {
		global.GVA_LOG.Info("setLockState Failed to bind a queue", zap.Error(err))
	}

	msgs, err := ch.Consume(
		"setLockState", // queue
		"",             // consumer
		true,           // auto ack
		false,          // exclusive
		false,          // no local
		false,          // no wait
		nil,            // args
	)
	if err != nil {
		global.GVA_LOG.Info("setLockState Failed to register a consumer", zap.Error(err))
	}

	var forever chan struct{}
	go func() {
		for d := range msgs {
			log.Printf(" [x] %s", d.Body)
			var req systemReq.SetLockState
			err = json.Unmarshal(d.Body, &req)
			if err != nil {
				global.GVA_LOG.Error("setLockState 解析失败", zap.String("请求参数", string(d.Body)))
				continue
			}
			var sn system.Sn
			err = global.GVA_DB.Where("value = ?", req.Sn).First(&sn).Error
			if err != nil {
				continue
			}
			if req.Status == 1 {
				global.GVA_DB.Model(&system.Sn{}).Where("value = ?", req.Sn).Update("is_online", req.Status)
				todayStr := time.Now().Format("20060102")
				todayInt, _ := strconv.Atoi(todayStr)
				todayInt64 := int64(todayInt)
				var onlineData system.OnlineDatum
				global.GVA_DB.Where(system.OnlineDatum{Sn: &req.Sn, AdminID: &sn.AdminID, OnlineTime: &todayInt64}).FirstOrCreate(&onlineData)
			} else {
				nowTime := time.Now().Unix()
				global.GVA_DB.Model(&system.Sn{}).Where("value = ?", req.Sn).Updates(system.Sn{IsOnline: &req.Status, Offlinetime: &nowTime})
			}
		}
	}()
	log.Printf(" [*] Waiting for logs. To exit press CTRL+C")
	<-forever

}

func (sp *SnProcess) UpdateSnOffLineTime() {
	// 订阅sn在线在线状态
	if token := global.GVA_MQTT.Subscribe("MQTT/T/UPDATE_DEVICE_INFO/#", 0, onMessageReceived); token.Wait() && token.Error() != nil {
		log.Fatal(token.Error())
		return
	}

}

// MQTT 消息回调函数
func onMessageReceived(client mqtt.Client, msg mqtt.Message) {
	// 解析消息主题和内容
	topicParts := strings.Split(msg.Topic(), "/")
	snStr := topicParts[3] // 获取学生ID
	sn := snStr[3:]

	type message struct {
		Timestamp string
		Message   string
	}
	var status message
	err := json.Unmarshal(msg.Payload(), &status)
	if err != nil {
		//global.GVA_LOG.Info("解析sn失败", zap.Any("在线状态解析失败", status))
		return
	}
	//fmt.Printf("sn:%s 在线状态:%s", sn, status.Message)
	// 根据学生状态更新学习时间
	if status.Message == "1" {
		isOnline := int64(1)
		err = global.GVA_DB.Model(&system.Sn{}).Where("value=?", sn).Update("is_online", isOnline).Error
		if err != nil {
			global.GVA_LOG.Error("修改sn上线状态失败", zap.String("sn", sn), zap.Error(err))
			return
		}
	} else {
		offlineTime, err := strconv.Atoi(status.Timestamp)
		if err != nil {
			global.GVA_LOG.Error("无法将Timestamp转换为整数", zap.Error(err))
			return
		}
		offlineTimeInt64 := int64(offlineTime/1000)
		isOnline := int64(2)
		err = global.GVA_DB.Model(&system.Sn{}).Where("value=?", sn).Updates(system.Sn{Offlinetime: &offlineTimeInt64, IsOnline: &isOnline}).Error
		if err != nil {
			global.GVA_LOG.Error("修改sn离线时间失败", zap.String("sn", sn), zap.Int64("offlineTime", offlineTimeInt64), zap.Error(err))
		}
	}
}